#include "guiterm.hpp"

BackendConnection::BackendConnection()
{
	string guishExe = QCoreApplication::applicationDirPath().toStdString()+"/guishell_sh";
	guishExe = quoteProtectString(guishExe.c_str());
	
	child = new QProcess();
	
	connect(child, SIGNAL(started()), this, SLOT(started()));
	connect(child, SIGNAL(readyReadStandardOutput()), this, SLOT(readReady()));
	connect(child, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finished(int,QProcess::ExitStatus)));
	connect(child, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWritten(qint64)));
	
	this->host = new ServerConnection(this);
	
	connect(this, SIGNAL(idle()), host, SLOT(idle()), Qt::QueuedConnection);
	
	child->start(guishExe.c_str());
	//child->start(guishExe, QIODevice::ReadWrite | QIODevice::Unbuffered);
	if(!child->waitForStarted(500)) {
		trace << "Failed to start child\n";
		return;
	}
}

BackendConnection::~BackendConnection()
{
}

void BackendConnection::sendData(const char *data, int len)
{
	writeBuf.append(len, data);
	attemptWrite();
}

ServerConnection *BackendConnection::getFirstHost()
{
	return host;
}

bool BackendConnection::isIdle()
{
	return (writeBuf.getLen() == 0);
}

void BackendConnection::started()
{
}

void BackendConnection::readReady()
{
	QByteArray output = child->readAllStandardOutput();
	if(output.size() > 0)
		host->receivedData(output.length(), output.constData());
}

void BackendConnection::finished(int code, QProcess::ExitStatus status)
{
	QByteArray err = child->readAllStandardError();
	
	if(err.count() > 0) {
		err.append((char)0);
		QString message = QString((const char*)err.data());
		disconnected(true, message);
	} else if(child->exitStatus() == QProcess::CrashExit) {
		disconnected(true, "Shell crashed");
	} else if(child->exitCode()) {
		char buf[512];
		sprintf(buf, "Shell returned %i.", (int)child->exitCode());
		disconnected(true, buf);
	} else {
		disconnected(false, "");
	}
}

void BackendConnection::bytesWritten(qint64 size)
{
	if(writeBuf.getLen() && !child->bytesToWrite())
		attemptWrite();
}

void BackendConnection::disconnected(bool error, QString message)
{
	host->disconnected(error, message.toStdString());
}

void BackendConnection::attemptWrite()
{
	if(!child) return;
	
	qint64 bytesWritten = child->write(writeBuf.getData(), writeBuf.getLen());
	writeBuf.popFront(bytesWritten);
	child->waitForBytesWritten(10);
	
	if(!writeBuf.getLen())
		QTimer::singleShot(0, host, SLOT(idle()));
}

